//
//  WCBuildConfiguration.m
//  WabbitCode
//
//  Created by William Towe on 12/4/08.
//  Copyright 2008 Revolution Software. All rights reserved.
//

#import "WCBuildConfiguration.h"
#import "WCMacros.h"
#import "WCBuildDefine.h"
#import "NSArray+WCExtensions.h"
#import "NSDictionary+WCExtensions.h"
#import "WCBuildStep.h"
#import "WCTextFile.h"
#import "WCIncludeDirectory.h"


#define kWCBCIsConfigurationActiveKey @"isConfigurationActive"
#define kWCBCDefinesKey @"defines"
#define kWCBCBuildTargetKey @"buildTarget"
#define kWCBCCreateCodeListingKey @"createCodeListing"
#define kWCBCCreateSymbolTableKey @"createSymbolTable"
#define kWCBCLabelsAndMacrosAreCaseSensitiveKey @"labelsAndMacrosAreCaseSensitive"
#define kWCBCIncludeDirectoriesKey @"includeDirectories"

NSString *kWCBCCreateCodeListingOptionName = nil;
NSString *kWCBCCreateSymbolTableOptionName = nil;
NSString *kWCBCLabelsAndMacrosAreCaseSensitiveOptionName = nil;
NSString *kWCBCDefinesOptionName = nil;
NSString *kWCBCIncludeDirectoriesOptionName = nil;

NSString *kWCBCBuildConfigurationNameDidChangeNotification = @"kWCBCBuildConfigurationNameDidChangeNotification";


@implementation WCBuildConfiguration
#pragma mark *** Subclass Overrides ***
+ (void)initialize {
	kWCBCCreateCodeListingOptionName = [NSLocalizedString(@"Create Code Listing",@"build configuration create code listing option name") retain];
	kWCBCCreateSymbolTableOptionName = [NSLocalizedString(@"Create Symbol Table",@"build configuration create symbol table option name") retain];
	kWCBCLabelsAndMacrosAreCaseSensitiveOptionName = [NSLocalizedString(@"Labels and Macros Are Case Sensitive",@"build configuration labels and macros are case sensitive option name") retain];
	kWCBCDefinesOptionName = [NSLocalizedString(@"Defines",@"build configuration defines option name") retain];
	kWCBCIncludeDirectoriesOptionName = [NSLocalizedString(@"Include Directories",@"build configuration include directories option name") retain];
}

+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key {
	if ([key isEqualToString:@"image"])
		return [NSSet setWithObjects:@"isConfigurationActive", nil];
	return [super keyPathsForValuesAffectingValueForKey:key];
}

- (void)setName:(NSString *)value {
	[super setName:value];
	[[NSNotificationCenter defaultCenter] postNotificationName:kWCBCBuildConfigurationNameDidChangeNotification object:self];
}

#ifdef WCDEBUG
- (NSString *)description {
	return [NSString stringWithFormat:@"Class: %@\nisActive: %@\ndefines: %@", NSStringFromClass([self class]), ([self isConfigurationActive])?@"YES":@"NO", _defines];
}
#endif

- (void)dealloc {
	[_defines release];
	[_includeDirectories release];
	[super dealloc];
}
- (BOOL)isLeaf {
	return NO;
}

- (NSImage *)icon {
	if ([self isConfigurationActive]) {
		NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize(16, 16)];
		NSImage *old = [NSImage imageNamed:@"BuildConfiguration16x16"];
		NSImage *badge = [NSImage imageNamed:@"ActiveBadge8x8"];
		[old setSize:NSMakeSize(16, 16)];
		[badge setSize:NSMakeSize(8, 8)];
		
		[image lockFocus];
		[old compositeToPoint:NSZeroPoint operation:NSCompositeCopy];
		[badge compositeToPoint:NSMakePoint(8, 0) operation:NSCompositeSourceOver];
		[image unlockFocus];
		
		return [image autorelease];
	}
	return [NSImage imageNamed:@"BuildConfiguration16x16"];
}


- (BOOL)canGetInfo {
	return YES;
}

- (BOOL)canCopyDuringDrag {
	return YES;
}

- (BOOL)canCopyNodeOnDrop {
	return YES;
}

- (NSArray *)acceptedDropTypes {
	static NSArray *types = nil;
	if (!types)
		types = [[NSArray alloc] initWithObjects:[WCBuildStep class], [WCTextFile class], nil];
	return types;
}

- (NSString *)nodeToolTip {
	NSMutableString *string = [NSMutableString stringWithFormat:([self isConfigurationActive])?NSLocalizedString(@"Build Configuration Name: %@ (Active)",@"nodeToolTip for Active Build Configuration"):NSLocalizedString(@"Build Configuration Name: %@",@"nodeToolTip for Build Configuration"), [self name]];
	
	if (![[self childNodes] count])
		return [[string copy] autorelease];
	
	[string appendFormat:NSLocalizedString(@"\nTotal Build Steps: %u\n",@"Total Build Steps for Build Configuration"), [[self childNodes] count]];
	
	for (WCBuildStep *step in [self childNodes])
		[string appendFormat:@"%@\n", [step nodeToolTip]];
	
	[string deleteCharactersInRange:NSMakeRange([string length]-1, 1)];
	
	return [[string copy] autorelease];
}

#pragma mark NSCoding Protocol
- (id)initWithCoder:(NSCoder *)coder {
	if (!(self = [super initWithCoder:coder]))
		return nil;
	
	_isConfigurationActive = [coder decodeBoolForKey:kWCBCIsConfigurationActiveKey];
	_createCodeListing = [coder decodeBoolForKey:kWCBCCreateCodeListingKey];
	_createSymbolTable = [coder decodeBoolForKey:kWCBCCreateSymbolTableKey];
	_labelsAndMacrosAreCaseSensitive = [coder decodeBoolForKey:kWCBCLabelsAndMacrosAreCaseSensitiveKey];
	_defines = [[coder decodeObjectForKey:kWCBCDefinesKey] retain];
	_includeDirectories = [[coder decodeObjectForKey:kWCBCIncludeDirectoriesKey] retain];
	_buildTarget = [coder decodeObjectForKey:kWCBCBuildTargetKey];
	
	return self;
}
- (void)encodeWithCoder:(NSCoder *)coder {
	[super encodeWithCoder:coder];
	[coder encodeBool:_isConfigurationActive forKey:kWCBCIsConfigurationActiveKey];
	[coder encodeObject:_defines forKey:kWCBCDefinesKey];
	[coder encodeConditionalObject:_buildTarget forKey:kWCBCBuildTargetKey];
	[coder encodeBool:_createCodeListing forKey:kWCBCCreateCodeListingKey];
	[coder encodeBool:_createSymbolTable forKey:kWCBCCreateSymbolTableKey];
	[coder encodeBool:_labelsAndMacrosAreCaseSensitive forKey:kWCBCLabelsAndMacrosAreCaseSensitiveKey];
	[coder encodeObject:_includeDirectories forKey:kWCBCIncludeDirectoriesKey];
}
#pragma mark NSCopying Protocol
- (id)copyWithZone:(NSZone *)zone {
	WCBuildConfiguration *copy = [super copyWithZone:zone];
	
	copy->_isConfigurationActive = _isConfigurationActive;
	copy->_createCodeListing = _createCodeListing;
	copy->_createSymbolTable = _createSymbolTable;
	copy->_labelsAndMacrosAreCaseSensitive = _labelsAndMacrosAreCaseSensitive;
	copy->_buildTarget = _buildTarget;
	copy->_defines = [_defines retain];
	copy->_includeDirectories = [_includeDirectories retain];
	
	return copy;
}
#pragma mark NSMutableCopying Protocol
- (id)mutableCopyWithZone:(NSZone *)zone {
	WCBuildConfiguration *copy = [super mutableCopyWithZone:zone];
	
	copy->_isConfigurationActive = NO;
	copy->_createCodeListing = _createCodeListing;
	copy->_createSymbolTable = _createSymbolTable;
	copy->_labelsAndMacrosAreCaseSensitive = _labelsAndMacrosAreCaseSensitive;
	copy->_buildTarget = _buildTarget;
	
	for (WCBuildDefine *define in [self defines])
		[[copy defines] addObject:[[define mutableCopy] autorelease]];
	
	for (WCIncludeDirectory *include in [self includeDirectories])
		[[copy includeDirectories] addObject:[[include mutableCopy] autorelease]];
	
	return copy;
}
#pragma mark *** Public Methods ***
- (NSCell *)cellForOptionName:(NSString *)optionName; {
	if ([optionName isEqualToString:kWCBCCreateCodeListingOptionName]) {
		NSButtonCell *cell = [[[NSButtonCell alloc] init] autorelease];
		
		[cell setButtonType:NSSwitchButton];
		[cell setImagePosition:NSImageOnly];
		//[cell setTitle:nil];
		[cell setControlSize:NSSmallControlSize];
		
		return cell;
	}
	else if ([optionName isEqualToString:kWCBCCreateSymbolTableOptionName]) {
		NSButtonCell *cell = [[[NSButtonCell alloc] init] autorelease];
		
		[cell setButtonType:NSSwitchButton];
		[cell setImagePosition:NSImageOnly];
		//[cell setTitle:nil];
		[cell setControlSize:NSSmallControlSize];
		
		return cell;
	}
	else if ([optionName isEqualToString:kWCBCLabelsAndMacrosAreCaseSensitiveOptionName]) {
		NSButtonCell *cell = [[[NSButtonCell alloc] init] autorelease];
		
		[cell setButtonType:NSSwitchButton];
		[cell setImagePosition:NSImageOnly];
		//[cell setTitle:nil];
		[cell setControlSize:NSSmallControlSize];
		
		return cell;
	}
	else if ([optionName isEqualToString:kWCBCDefinesOptionName]) {
		NSTextFieldCell *cell = [[[NSTextFieldCell alloc] init] autorelease];
		
		[cell setControlSize:NSSmallControlSize];
		[cell setLineBreakMode:NSLineBreakByTruncatingTail];
		[cell setFont:[NSFont controlContentFontOfSize:[NSFont systemFontSizeForControlSize:[cell  controlSize]]]];
		
		return cell;
	}
	else if ([optionName isEqualToString:kWCBCIncludeDirectoriesOptionName]) {
		NSTextFieldCell *cell = [[[NSTextFieldCell alloc] init] autorelease];
		
		[cell setControlSize:NSSmallControlSize];
		[cell setLineBreakMode:NSLineBreakByTruncatingTail];
		[cell setFont:[NSFont controlContentFontOfSize:[NSFont systemFontSizeForControlSize:[cell  controlSize]]]];
	}
	return nil;
}

- (id)valueForOptionName:(NSString *)optionName; {
	if ([optionName isEqualToString:kWCBCCreateCodeListingOptionName]) {
		return NSNumberWithBool([self createCodeListing]);
	}
	else if ([optionName isEqualToString:kWCBCCreateSymbolTableOptionName]) {
		return NSNumberWithBool([self createSymbolTable]);
	}
	else if ([optionName isEqualToString:kWCBCLabelsAndMacrosAreCaseSensitiveOptionName]) {
		return NSNumberWithBool([self labelsAndMacrosAreCaseSensitive]);
	}
	else if ([optionName isEqualToString:kWCBCDefinesOptionName]) {
		return [self processedDefinesAsString];
	}
	else if ([optionName isEqualToString:kWCBCIncludeDirectoriesOptionName]) {
		return [[[self includeDirectories] valueForKey:@"name"] componentsJoinedByString:@", "];
	}
	return nil;
}

- (void)setObjectValue:(id)value forOptionName:(NSString *)optionName; {
	if ([optionName isEqualToString:kWCBCCreateCodeListingOptionName]) {
		[self setCreateCodeListing:[value boolValue]];
	}
	else if ([optionName isEqualToString:kWCBCCreateSymbolTableOptionName]) {
		[self setCreateSymbolTable:[value boolValue]];
	}
	else if ([optionName isEqualToString:kWCBCLabelsAndMacrosAreCaseSensitiveOptionName]) {
		[self setLabelsAndMacrosAreCaseSensitive:[value boolValue]];
	}
}

- (void)recursivelyAddIncludeDirectoriesWithDirectoryPath:(NSString *)directoryPath; {
	[self recursivelyAddIncludeDirectoriesWithDirectoryPath:directoryPath includeRootDirectory:NO];
}

- (void)recursivelyAddIncludeDirectoriesWithDirectoryPath:(NSString *)directoryPath includeRootDirectory:(BOOL)includeRootDirectory; {
	if (includeRootDirectory) {
		[[self includeDirectories] addObject:[WCIncludeDirectory includeDirectoryWithDirectoryPath:directoryPath forBuildConfiguration:self]];
	}
	
	BOOL flag = NO;
	for (NSString *relativePath in [[NSFileManager defaultManager] enumeratorAtPath:directoryPath]) {
        if (![relativePath hasPrefix:@"."] && [[NSFileManager defaultManager] fileExistsAtPath:[directoryPath stringByAppendingPathComponent:relativePath] isDirectory:&flag] && flag && ![[NSWorkspace sharedWorkspace] isFilePackageAtPath:[directoryPath stringByAppendingPathComponent:relativePath]])
			
			[[self includeDirectories] addObject:[WCIncludeDirectory includeDirectoryWithDirectoryPath:[directoryPath stringByAppendingPathComponent:relativePath] forBuildConfiguration:self]];
	}
}
#pragma mark Accessors
@synthesize isConfigurationActive=_isConfigurationActive,createCodeListing=_createCodeListing,createSymbolTable=_createSymbolTable,labelsAndMacrosAreCaseSensitive=_labelsAndMacrosAreCaseSensitive,buildTarget=_buildTarget,includeDirectories=_includeDirectories,defines=_defines;

@dynamic processedIncludeDirectories;
- (NSArray *)processedIncludeDirectories {
	NSMutableArray *array = [NSMutableArray array];
	
	for (WCIncludeDirectory *include in [self includeDirectories])
		[array addObject:[NSString stringWithFormat:@"-I%@",[include directoryPath]]];
	
	return [[array copy] autorelease];
}

- (NSMutableArray *)defines {
	if (!_defines) {
		_defines = [[NSMutableArray alloc] init];
	}
	return _defines;
}

- (NSMutableArray *)includeDirectories {
	if (!_includeDirectories) {
		_includeDirectories = [[NSMutableArray alloc] init];
	}
	return _includeDirectories;
}

@dynamic processedDefines;
- (NSArray *)processedDefines {
	return [[self defines] valueForKey:@"nameAndValue"];
}

@dynamic processedDefinesAsString;
- (NSString *)processedDefinesAsString {
	return [[self processedDefines] componentsJoinedByString:@" "];
}

@dynamic numberOfOptions;
- (NSUInteger)numberOfOptions {
	static NSUInteger count = 0;
	if (!count) {
		count = [[self arrayOfOptionNames] count];
	}
	return count;
}

@dynamic arrayOfOptionNames;
- (NSArray *)arrayOfOptionNames {
	return [NSArray arrayWithObjects:kWCBCCreateCodeListingOptionName, kWCBCLabelsAndMacrosAreCaseSensitiveOptionName, kWCBCDefinesOptionName, kWCBCIncludeDirectoriesOptionName, nil];
}
#pragma mark Creation

+ (WCBuildConfiguration *)buildConfigWithName:(NSString *)name forBuildTarget:(WCBuildTarget *)buildTarget; {
	return [[[[self class] alloc] initWithName:name forBuildTarget:buildTarget] autorelease];
}
				  
- (id)initWithName:(NSString *)name forBuildTarget:(WCBuildTarget *)buildTarget; {
	if (!(self = [super initWithNodeName:name]))
		return nil;

	_buildTarget = buildTarget;
	NSRange range = [[self name] rangeOfCharacterFromSet:[NSCharacterSet whitespaceCharacterSet]];
	if (range.location == NSNotFound)
		[[self defines] addObject:[WCBuildDefine buildDefineWithName:[name uppercaseString]]];
	
	return self;
}

@end
